package com.naiterui.ehp.bs.payment.service;

import com.github.binarywang.wxpay.exception.WxPayException;
import com.naiterui.ehp.bp.utils.payment.bo.OrderStatusResultBO;
import com.naiterui.ehp.bp.utils.payment.bo.RefundRequestBO;
import com.naiterui.ehp.bp.utils.payment.bo.UnifiedOrderRequestBO;
import com.naiterui.ehp.bp.utils.payment.bo.UnifiedOrderResultBO;
import com.naiterui.ehp.bs.payment.exception.NotifyRefundException;
import com.naiterui.ehp.bs.payment.exception.PaymentBusinessException;

/**
 * 支付功能相关接口：包括统一下单，查询订单，关闭订单，退款，回调通知接口
 * 具体接口请看接口注释
 *
 * @date 2017年09月09日
 * @since 1.0.0
 */
public interface IOrderService {

    /**
     * 统一下单接口
     * 在发起支付前，需要调用统一下单接口，获取"预支付交易会话标识"
     * 如果此接口调用成功，那么将会将预支付信息存入MySQL，并且记录预支付生成的渠道,期间如果有人在调用，那么直接返回预支付信息，
     * 如果预支付信息过期，那么重新调用统一下单接口，并且将之前的预支付信息设置失效,
     * 如果三方接口不能使用的话，那么系统会根据内置的支付策略来切换支付渠道，这里必须保证order_pre_payment_info
     * 表中只能有一个可以使用的预支付信息，不能存在多个渠道可以使用的预支付信息，因为如果支付渠道是多个的话，无法确定此订单使用哪个渠道支付，后面的查询订单和退款功能将会出现使用问题
     *
     * @param request 请求对象，注意一些参数如notifyUrl等不用设置，方法内会自动从配置对象中获取到（前提是对应配置中已经设置）
     *
     * @return 返回预支付信息
     *
     * @date 2017年09月09日
     * @since 1.0.0
     */
    UnifiedOrderResultBO unifiedOrder(UnifiedOrderRequestBO request) throws WxPayException;

    /**
     * 查询订单(详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2)
     * 该接口提供所有微信支付订单的查询，商户可以通过查询订单接口主动查询订单状态，完成下一步的业务逻辑。
     * 需要调用查询接口的情况：
     * ◆ 当商户后台、网络、服务器等出现异常，商户系统最终未接收到支付通知；
     * ◆ 调用支付接口后，返回系统错误或未知交易状态情况；
     * ◆ 调用被扫支付API，返回USERPAYING的状态；
     * ◆ 调用关单或撤销接口API之前，需确认支付状态；
     * 接口地址：https://api.mch.weixin.qq.com/pay/orderquery
     *
     * @param orderSn 商户系统内部的订单号 不能为空
     *
     * @return 支付状态 {@link com.naiterui.ehp.bp.constants.PayStatus}
     *
     * @throws PaymentBusinessException 支付异常
     * @date 2017年09月09日
     * @since 1.0.0
     */
    OrderStatusResultBO queryOrderPayStatus(String orderSn) throws PaymentBusinessException, WxPayException;

    /**
     * 关闭订单
     * 应用场景
     * 以下情况需要调用关单接口：
     * 1. 商户订单支付失败需要生成新单号重新发起支付，要对原订单号调用关单，避免重复支付；
     * 2. 系统下单后，用户支付超时，系统退出不再受理，避免用户继续，请调用关单接口。
     * 注意：订单生成后不能马上调用关单接口，最短调用时间间隔为5分钟。
     * 接口地址：https://api.mch.weixin.qq.com/pay/closeorder
     * 是否需要证书： 不需要。
     *
     * @param orderSn 商户系统内部的订单号 不能为空
     *
     * @throws PaymentBusinessException 支付异常
     * @date 2017年09月09日
     * @since 1.0.0
     */
    void closeOrder(String orderSn) throws PaymentBusinessException, WxPayException;

    /**
     * 微信支付-申请退款
     * 当交易发生之后一段时间内，由于买家或者卖家的原因需要退款时，卖家可以通过退款接口将支付款退还给买家，微信支付将在收到退款请求并且验证成功之后，按照退款规则将支付款按原路退到买家帐号上。
     * 注意：
     * 1、交易时间超过一年的订单无法提交退款
     * 2、微信支付退款支持单笔交易分多次退款，多次退款需要提交原支付订单的商户订单号和设置不同的退款单号。申请退款总金额不能超过订单金额。 一笔退款失败后重新提交，请不要更换退款单号，请使用原商户退款单号
     * 3、请求频率限制：150qps，即每秒钟正常的申请退款请求次数不超过150次 错误或无效请求频率限制：6qps，即每秒钟异常或错误的退款申请请求不超过6次
     * 4、每个支付订单的部分退款次数不能超过50次
     * 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
     * 接口链接：https://api.mch.weixin.qq.com/secapi/pay/refund
     *
     * @param request 退款信息
     *
     * @throws PaymentBusinessException 支付异常
     * @throws NotifyRefundException    退款通知异常
     * @date 2017年09月09日
     * @since 1.0.0
     */
    void refund(RefundRequestBO request) throws PaymentBusinessException, NotifyRefundException, WxPayException;

    /**
     * 此方法会将xml转换成对应的实体，并且校验参数，验证签名是否正确，校验通过后会通过订单号查询service_pay_info表中是否有记录，如果存在，那么会校验订单的支付状态，
     * 如果是带待支付状态，会校验订单支付金额和订单金额是否一致如果一致则会通知其他业务系统
     *
     * @param xml 三方支付系统回调通知结果
     *
     * @date 2017年09月09日
     * @since 1.0.0
     */
    void notify(String xml) throws PaymentBusinessException, WxPayException;

}
